#include "file_manager.h"

namespace file_manager{

/***********************************************************
 * 文件操作
 ***********************************************************/
// 文件创建
bool CreateFile(string file_path){
    try{
        fs::path path(file_path);
        // 打开文件（如果文件不存在，则创建它）
        std::ofstream file(path.string());
        if(!file) {
            throw std::ios_base::failure("Failed to create the file.");
        }
        // 关闭文件
        file.close();
        // std::cout << "File created successfully: " << path << std::endl;
        return true;
    } 
    catch (const fs::filesystem_error& ex){
        std::cerr << ex.what() << std::endl;
    }
    catch (const std::exception& ex) {
        std::cerr << "An error occurred: " << ex.what() << std::endl;
    }
    return false;
}

// 文件删除
bool DeleteFile(string file_path){
    try{
        fs::path path(file_path);
        return fs::remove(path);
    }
    catch (const fs::filesystem_error& ex){
        std::cerr << ex.what() << std::endl;
    }
    return false;
}

// 文件复制
bool CopyFile(string old_file_path, string new_file_path){
    try{
        fs::path fs_source_path(old_file_path);
        fs::path fs_target_name(new_file_path);
        fs::copy_file(fs_source_path, fs_target_name);
        return true;
    }
    catch (const fs::filesystem_error& ex){
        std::cerr << ex.what() << std::endl;
    }
    return false;
}

// 文件大小 单位M
float GetFileSize(string file_path){
    try{
        fs::path path(file_path);
        uintmax_t size = 0;    
        if(fs::is_regular_file(path)) {
            size = fs::file_size(path);
        }
        long B2M = 1024 * 1024;
        return (float)size / B2M;
    }
    catch (const fs::filesystem_error& ex){
        std::cerr << ex.what() << std::endl;
    }
    return 0.0;
}

// 文件移动到指定文件夹
bool MoveFileToDir(string old_file_path, string dir_path){
    try{
        if(IsExists(old_file_path) && IsExists(dir_path)){
            fs::path fs_old_file(old_file_path);
            fs::path fs_dir_path(dir_path);
            std::string fileName = fs_old_file.filename().string();
            fs::path fullPath = fs_dir_path / fileName;
            fs::rename(fs_old_file, fullPath);
            return true;
        }
    }
    catch (const fs::filesystem_error& ex){
        std::cerr << ex.what() << std::endl;
    }
    return false;
}

// 是否是文件判断
bool IsFile(string file_path){
    try{
        fs::path path(file_path);
        if(fs::exists(path)){
            return fs::is_regular_file(path);
        }
        return false;
    }
    catch (const fs::filesystem_error& ex){
        std::cerr << ex.what() << std::endl;
    }
}

/***********************************************************
 * 文件/文件夹通用操作
 ***********************************************************/
// 文件/文件夹是否存在
bool IsExists(string file_path){
    try{
        fs::path path(file_path);
        return fs::exists(path);
    }
    catch (const fs::filesystem_error& ex){
        std::cerr << ex.what() << std::endl;
    }
    return false;
}

// 文件/文件夹创建时间
time_t GetCreateTime(string file_path){
    try{
        struct stat statbuf;
        int result = stat(file_path.c_str(), &statbuf);
        return statbuf.st_ctime;
    }
    catch (const fs::filesystem_error& ex){
        std::cerr << ex.what() << std::endl;
    }
    return 0;
}

// 文件/文件夹修改时间
time_t GetModifyTime(string file_path){
    try{
        fs::path path(file_path);
        return fs::last_write_time(path);
    }
    catch (const fs::filesystem_error& ex){
        std::cerr << ex.what() << std::endl;
    }
    return 0;
}

// 文件/文件夹信息
FileInfo GetInfo(string file_path){
    FileInfo file_info;
    try{
        file_info.is_file = IsFile(file_path);
        file_info.is_dir = IsDir(file_path);
        file_info.is_exists = IsExists(file_path);
        
        file_info.file_path = file_path;
        string::size_type iPos = file_path.find_last_of('/') + 1;
        file_info.file_name = file_path.substr(iPos, file_path.length() - iPos);
        string::size_type suffix_iPos = file_info.file_name.find_last_of('.') + 1;
        file_info.suffix = file_info.file_name.substr(suffix_iPos); 
        file_info.file_name_no_suffix = file_info.file_name.substr(0, suffix_iPos-1);   
        if(file_info.is_exists){
            if(file_info.is_file)
                file_info.file_size = GetFileSize(file_path);
            if(file_info.is_dir)
                file_info.file_size = GetDirSize(file_path);
            file_info.c_time = GetCreateTime(file_path);
            file_info.m_time = GetModifyTime(file_path);
        }
    }
    catch (const fs::filesystem_error& ex){
        std::cerr << ex.what() << std::endl;
    }
    return file_info;
}

// 文件/文件夹重命名
bool Rename(string old_file_path, string new_file_path){
    try{
        fs::path fs_source_path(old_file_path);
        fs::path fs_target_name(new_file_path);
        fs::rename(fs_source_path, fs_target_name);
        return true;
    }
    catch (const fs::filesystem_error& ex){
        std::cerr << ex.what() << std::endl;
    } 
    return false;
}

/***********************************************************
 * 文件夹操作
 ***********************************************************/
// 文件夹创建
bool CreateDir(string dir_path){
    try{
        fs::path path(dir_path);
        return fs::create_directories(path);
    }
    catch (const fs::filesystem_error& ex){
        std::cerr << ex.what() << std::endl;
    }
    return false;
}

// 文件夹删除
bool DeleteDir(string dir_path){
    try{
        fs::path path(dir_path);
        return fs::remove_all(path);
    }
    catch (const fs::filesystem_error& ex){
        std::cerr << ex.what() << std::endl;
    }
}


// 递归复制目录文件
void copy_directory_recursive(const fs::path& source, const fs::path& target){
    if (!fs::exists(target)) {
        fs::create_directories(target);
    }
    for (fs::directory_iterator file(source); file != fs::directory_iterator(); ++file) {
        const fs::path current(file->path());
        const fs::path new_target = target / current.filename();

        if (fs::is_directory(current)){
            copy_directory_recursive(current, new_target);
        } else {
            fs::copy_file(current, new_target, fs::copy_option::overwrite_if_exists);
        }
    }
}

// 文件夹复制
bool CopyDir(string old_dir_path, string new_dir_path){
    try{
        fs::path fs_source_dir(old_dir_path);
        fs::path fs_target_dir(new_dir_path);
        fs::create_directories(fs_target_dir);
        fs::copy_directory(fs_source_dir, fs_target_dir);   //仅复制目录文件
        // 递归复制目录下的所有文件
        copy_directory_recursive(fs_source_dir, fs_target_dir);
        return true;
    }
    catch (const fs::filesystem_error& ex){
        std::cerr << ex.what() << std::endl;
    }
    return false;
}

// 文件夹大小 单位M
float GetDirSize(string dir_path){
    try{
        fs::path fs_dir_path(dir_path);
        uintmax_t size = 0;

        // 遍历目录下的所有文件和子文件夹
        for(const auto& entry : fs::recursive_directory_iterator(fs_dir_path)) {
            try{
                // 如果是普通文件，累加文件大小
                if (fs::is_regular_file(entry)) {
                    size += fs::file_size(entry);
                }
            } catch (const fs::filesystem_error& ex) {
                std::cerr << "Error accessing: " << entry.path().string() << " - " << ex.what() << std::endl;
            }
        }
        long B2M = 1024 * 1024;
        return (float)size / B2M;    
    }
    catch (const fs::filesystem_error& ex){
        std::cerr << ex.what() << std::endl;
    }
}


// 文件夹移动到指定文件夹
bool MoveDirToDir(string old_dir_path, string dir_path){
    try{
        fs::path fs_source_dir(old_dir_path);
        fs::path fs_target_dir(dir_path);
        fs::create_directories(fs_target_dir);
        fs::rename(fs_source_dir, fs_target_dir);   
    }
    catch (const fs::filesystem_error& ex){
        std::cerr << ex.what() << std::endl;
    }
}

// 是否是文件夹
bool IsDir(string dir_path){
    try{      
        fs::path path(dir_path);
        if(fs::exists(path)){
            return fs::is_directory(path);
        }
        return false;
    }
    catch (const fs::filesystem_error& ex){
        std::cerr << ex.what() << std::endl;
    }
}

// 获取文件列表 0 - 仅包含文件 1 - 仅包含文件夹 2 - 包含文件和文件夹
vector<string> ListDirWithDepth1(string dir_path, int cmd){
    vector<string> file_list;
    std::vector<fs::path> files;
    try{
        // 获取文件列表
        for(fs::directory_iterator iter(dir_path); iter != fs::directory_iterator(); ++iter) {
            if(fs::is_regular_file(iter->status())){
                if(cmd == 0 || cmd == 2)
                    files.emplace_back(iter->path());
            }
            if(fs::is_directory(iter->status())) {
                if(cmd == 1 || cmd == 2)
                    files.emplace_back(iter->path());
            }
        }
        // 按时间排序
        std::sort(files.begin(), files.end(), 
            [](const fs::path& a, const fs::path& b) {
                return fs::last_write_time(a) < fs::last_write_time(b);
            });
        // 转换为字符串目录
        for (const auto& file : files) {
            file_list.emplace_back(file.filename().string());
        }        
    }catch(const fs::filesystem_error& fs_ex){
        std::cerr << fs_ex.what() << std::endl;
    }
    return file_list;    
}

/***********************************************************
 * Ymal文件读写
 ***********************************************************/

// 处理带双引号的字符串读取异常导致写入也异常问题
// * data_en: " "  -> data_en: !<!> " "  -> data_en: " "
void ReplaceString(YAML::Node& node){
    if (node.IsScalar()) { // 如果节点是标量
        node = YAML::Node(node.as<std::string>()); // 将字符串替换为空值
    } else if (node.IsSequence()) { // 如果节点是序列
        for (std::size_t i = 0; i < node.size(); ++i) {
            YAML::Node nn = node[i];
            ReplaceString(nn); // 递归处理序列中的每个元素
        }
    } else if (node.IsMap()) { // 如果节点是映射
        for (auto it = node.begin(); it != node.end(); ++it) {
            // std::cerr << "key: " << it->first << std::endl;
            ReplaceString(it->second); // 递归处理映射中的每个值
        }
    }
}

// Ymal文件写入
bool WriteYamlFile(string file_path, YAML::Node& config){
    if(!config.IsNull())
        ReplaceString(config);
    ofstream fout(file_path);
    fout << config;
    fout.close();    
}

// Ymal文件读取
YAML::Node ReadYamlFile(string file_path){
    YAML::Node config;
    try{
        config = YAML::LoadFile(file_path);
        if(!config.IsNull())
            ReplaceString(config);
    }catch(YAML::BadFile &e) {
        std::cerr << "read error, file_path:" << file_path.c_str() << std::endl;
    }
    return config;    
}


/***********************************************************
 * Json文件读写
 ***********************************************************/
// Json文件写入
bool WriteJsonFile(string file_path, Json::Value& root){
    Json::StyledWriter sw;
    //输出到文件
    ofstream fout(file_path);
    fout << sw.write(root);
    fout.close();   

    // //直接输出
    // Json::FastWriter fw;
    // std::cerr << fw.write(root) << std::endl << std::endl;
    // //缩进输出
    // Json::StyledWriter sw;
    // std::cerr << sw.write(root) << std::endl << std::endl;
}

// Json文件读取
Json::Value ReadJsonFile(string file_path){
    Json::Reader reader;
    Json::Value root;
    ifstream in(file_path.c_str(), ios::binary);
    if(!in.good()){
        std::cerr << "[ReadJsonFile] bad file!" << std::endl;
        return root; 
    }
    reader.parse(in,root);
    return root;    
}

// 检测Json字段是否有效
bool CheckItemIsValid(Json::Value& json_data, string item){
    if(json_data.isMember(item) && !json_data[item].isNull()){
        return true;
    }
    return false;
}

}; // namespace file_manager